module(..., package.seeall) -- 使得文件中的函数在何处都可调用
require "pins" -- 用到了pin库，该库为luatask专用库，需要进行引用
require "sys"
require "uartTask"
require "audio"
require "math"
require "nvm"
require "send433RFSignal"
require "logGenerator"
require "utilsBySelf"
nvm.init("config.lua", true)
DoLampTask = true
local ttsStr = "预警系统演练"
local toneDowns, toneBreak, doToneTask, lampDowns, lampBreak, signalDowns,
      signalBreak, doSignalTask, relayDowns, relayBreak, doRelayTask,
      countDownSDrill, quake_intensity, equipment_clients, alarm433Bool,
      warnCancelTTSBroadcastCount, emergencyLightOpenBreak,
      doEmergencyLightOpen, flashLight = 0, false, true, 0, false, 0, false,
                                         true, 0, false, true, 0, 0, "", false,
                                         0, false, true, 0

TTS = 1
local setGpio9Fnc = pins.setup(pio.P0_9, 1) -- 静音设置（高电平静音）
local setGpio10Fnc = pins.setup(pio.P0_10, 0) -- 高音喇叭预警灯，应急灯继电器控制
local setGpio11Fnc = pins.setup(pio.P0_11, 0) -- Buzzer正常低电平，预警高电平
local setGpio17Fnc = pins.setup(pio.P0_17, 0) -- 地震预警测试音量控制音量25%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio16Fnc = pins.setup(pio.P0_16, 0) -- 地震预警测试音量控制音量50%，高电平为测试音量（音量小），低电平为正常音量（音量大）
local setGpio1Fnc = pins.setup(pio.P0_1, 0) -- 地震预警测试音量控制音量75%，高电平为测试音量（音量小），低电平为正常音量（音量大）
-- local setGpio12Fnc = pins.setup(pio.P0_12, 0) -- 报警灯
local setGpio2Fnc = pins.setup(pio.P0_2, 0) -- 蓝色
local setGpio3Fnc = pins.setup(pio.P0_3, 0) -- 红色
local setGpio13Fnc = pins.setup(pio.P0_13, 0) -- 绿色

-- 获取配置参数
local configIntensity, enable433, countDown, alertSound, alertLight,
      magnitudeConfig, centerIntensityConfig, emergencyLamp, relay, luminance,
      alertVolume, blueLimit, yellowLimit, orangeLimit, redLimit, afterSecond,
      exerciseText, cancelCount, hz, merchantNo, serialNumber, ackTopic,
      isOpenProject = tonumber(nvm.get("intensity")), nvm.get("enable433"),
                      tonumber(nvm.get("countDown")),
                      tonumber(nvm.get("alertSound")),
                      tonumber(nvm.get("alertLight")),
                      tonumber(nvm.get("magnitude")),
                      tonumber(nvm.get("centerIntensity")),
                      tonumber(nvm.get("emergencyLamp")),
                      tonumber(nvm.get("relay")),
                      tonumber(nvm.get("luminance")),
                      tonumber(nvm.get("alertVolume")),
                      tonumber(nvm.get("blueLimit")),
                      tonumber(nvm.get("yellowLimit")),
                      tonumber(nvm.get("orangeLimit")),
                      tonumber(nvm.get("redLimit")),
                      tonumber(nvm.get("afterSecond")), nvm.get("exerciseText"),
                      tonumber(nvm.get("cancelCount")), nvm.get("hz"),
                      nvm.get("thirdConfig")[4], nvm.get("info")[1],
                      nvm.get("thirdConfig")[9], nvm.get("isOpenProject")

-- 报警灯一秒闪烁次数
local function lampSlash1s(hzSet)
    local flashTime = 0
    if hzSet == "01" then
        flashTime = 1
    elseif hzSet == "02" then
        flashTime = 2
    elseif hzSet == "03" then
        flashTime = 3
    elseif hzSet == "04" then
        flashTime = 4
    elseif hzSet == "05" then
        flashTime = 5
    elseif hzSet == "06" then
        flashTime = 6
    elseif hzSet == "07" then
        flashTime = 7
    elseif hzSet == "08" then
        flashTime = 8
    elseif hzSet == "09" then
        flashTime = 9
    elseif hzSet == "10" then
        flashTime = 10
    end
    return flashTime
end
-- 烈度转换为阈值
local function intensity2Threshold(intensity2Th)
    local threhold = 0
    log.info("intensity2Th", intensity2Th, "blueLimit", blueLimit,
             "yellowLimit", yellowLimit, "redLimit", redLimit)
    if intensity2Th >= blueLimit and intensity2Th < yellowLimit then
        threhold = 1
    elseif intensity2Th >= yellowLimit and intensity2Th < orangeLimit then
        threhold = 2
    elseif intensity2Th >= orangeLimit and intensity2Th < redLimit then
        threhold = 3
    elseif intensity2Th >= redLimit then
        threhold = 4
    end
    return threhold
end
-- 应急照明灯打开任务
local function emergencyLightOpenTask()
    local emergencyLightOpenDowns = 0
    doEmergencyLightOpen = false
    log.info("应急照明灯打开！！")
    setGpio11Fnc(1)
    while emergencyLightOpenDowns >= 0 and emergencyLightOpenDowns <= 5400000 do
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        sys.wait(1000)
        if emergencyLightOpenBreak then
            emergencyLightOpenBreak = false
            break
        end
        emergencyLightOpenDowns = emergencyLightOpenDowns + 1
    end
    doEmergencyLightOpen = true
    sys.wait(5400000)
    setGpio11Fnc(0)
end
-- 继电器动作任务
local function relayTask(relayCount)
    relayDowns = relayCount
    setGpio10Fnc(1)
    log.info("继电器动作")
    doRelayTask = false
    while relayDowns > 0 do
        if relayBreak then
            relayDowns = 0
            relayBreak = false
            break
        end
        sys.wait(1000)
        if relayBreak then
            relayDowns = 0
            relayBreak = false
            break
        end
        relayDowns = relayDowns - 1
    end
    setGpio10Fnc(0)
    doRelayTask = true
end
-- 报警灯操作任务
local function alarmLampOperationTask(countD, publisher)
    local countFlash, colorSelect = lampSlash1s(hz), 0 -- 报警灯一秒闪烁次数
    if "Third" == publisher then
        colorSelect = flashLight
    else
        colorSelect = intensity2Threshold(quake_intensity)
        -- body
    end

    log.info("colorSelect:", colorSelect, "countFlash:", countFlash, "hz:", hz)
    DoLampTask = false
    lampDowns = countD
    setGpio10Fnc(1)
    while lampDowns >= 0 do
        log.info("lampBreak:", lampBreak)
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        if lampDowns % 2 == 0 then
            for i = 1, countFlash, 1 do
                if lampBreak then break end
                if colorSelect == 1 then -- 蓝灯闪烁一秒
                    setGpio2Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio2Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 2 then -- 黄灯闪烁一秒
                    setGpio3Fnc(1)
                    pins.setup(pio.P0_13, 1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    pins.setup(pio.P0_13, 0)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 3 then -- 橙灯闪烁一秒
                    pins.close(pio.P0_13)
                    setGpio3Fnc(1)
                    pio.pin.pwm(13, 200, 600, -1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    pio.pin.pwm(13, 0, 0, -1)
                    sys.wait(1000 / (2 * countFlash))
                elseif colorSelect == 4 then -- 红灯闪烁一秒
                    setGpio3Fnc(1)
                    sys.wait(1000 / (2 * countFlash))
                    setGpio3Fnc(0)
                    sys.wait(1000 / (2 * countFlash))
                end
            end
        elseif lampDowns % 2 == 1 then
            if lampBreak then
                lampDowns = 0
                lampBreak = false
                break
            end
            sys.wait(1000)
        end
        if lampBreak then
            lampDowns = 0
            lampBreak = false
            break
        end
        lampDowns = lampDowns - 1
    end
    setGpio10Fnc(0)
    DoLampTask = true
end

-- 发送433信号
local function send433SignalTask(countSignalDownS)
    local afterSecondCount = afterSecond
    doSignalTask = false
    setGpio9Fnc(0)
    signalDowns = countSignalDownS
    send433RFSignal.InterruptSendMsg = true
    send433RFSignal.sendMsgTask()
    if not send433RFSignal.TimeId then
        send433RFSignal.signalRF433SerialCommunication(signalDowns,
                                                       quake_intensity, "1",
                                                       alarm433Bool)
    end
    sys.wait(1000)
    signalDowns = signalDowns - 1
    while signalDowns > 0 do
        if signalDowns == 1 and afterSecondCount == 0 then
            alarm433Bool = true
        end
        if not send433RFSignal.TimeId then
            send433RFSignal.signalRF433SerialCommunication(signalDowns,
                                                           quake_intensity, "1",
                                                           alarm433Bool)
        end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        signalDowns = signalDowns - 1
    end
    if afterSecondCount > 0 then
        sys.taskInit(alarmLampOperationTask, afterSecondCount)
    end
    while afterSecondCount > 0 do
        log.info("afterSecondCount:", afterSecondCount)
        if afterSecondCount == 1 then alarm433Bool = true end
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        if not send433RFSignal.TimeId then
            log.info("继续响声音！！！")
            send433RFSignal.signalRF433SerialCommunication(1, quake_intensity,
                                                           "0", alarm433Bool)
        end
        sys.wait(1000)
        if signalBreak then
            signalBreak = false
            signalDowns = 0
            break
        end
        afterSecondCount = afterSecondCount - 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    doSignalTask = true
    alarm433Bool = false
    sys.wait(5000)
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束")
    elseif alertVolume <= 25 and alertVolume >= 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束")
    end -- 音量测试恢复正常（大音量）
end

-- 声音报警
local function alarmVoiceTask(countToneDownS)
    local waitCout = afterSecond
    doToneTask = false
    setGpio9Fnc(0)
    toneDowns = countToneDownS
    log.info("exerciseText", exerciseText)
    if string.len(exerciseText) > 0 then
        ttsStr = exerciseText
    elseif string.len(exerciseText) == 0 then
        ttsStr = "地震预警演练，地震预警演练"
    end
    audio.play(TTS, "TTS", ttsStr, 7)
    while toneDowns > 0 do
        log.info("setGpio1Fnc")
        if toneDowns <= 10 then
            log.info("tts voice")
            ttsStr = tostring(toneDowns)
            audio.play(TTS, "TTS", ttsStr, 7)
        end
        -- if math.fmod(countAlarmDrill, 12) == 0 then uartTask.write(0x0C) end
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        sys.wait(1000)
        if toneBreak then
            -- uartTask.write(0x0C)
            toneBreak = false
            toneDowns = 0
            break
        end
        toneDowns = toneDowns - 1
        -- countAlarmDrill = countAlarmDrill + 1
    end
    log.info("waitCout0", waitCout)
    while waitCout > 0 do
        log.info("waitCout1", waitCout)
        sys.wait(1000)
        waitCout = waitCout - 1
    end
    setGpio9Fnc(1) -- 报警结束设置静音
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(0)
        log.info("音量为75，结束，alarm")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(0)
        log.info("音量为50，结束，alarm")
    elseif alertVolume <= 25 and alertVolume >= 0 then
        setGpio17Fnc(0)
        log.info("音量为25，结束，alarm")
    end -- 音量测试恢复正常（大音量）
    doToneTask = true
end

-- 地震预警系统
-- 两个功能：1.预警系统演练（tts语音播报3遍同时报警音触发）
-- 入参：mqttData接收的预警信息
function EarthquakeWarningDrillSystem(tjsondata, publisherId,msgId)
    local msgCode, tClock, sysTime, eqlogInfo, errInfo = nil, os.date("*t"), "",
                                                         "", ""
    sysTime = utilsBySelf.GetSystemTime()
    if "false" == enable433 then
        enable433 = false
    elseif "true" == enable433 then
        enable433 = true
    end
    if alertVolume <= 75 and alertVolume > 50 then
        setGpio1Fnc(1)
        log.info("音量为75")
    elseif alertVolume <= 50 and alertVolume > 20 then
        setGpio16Fnc(1)
        log.info("音量为50")
    elseif alertVolume <= 25 and alertVolume >= 0 then
        setGpio17Fnc(1)
        log.info("音量为25")
    end
    if "Third" == publisherId then
        if isOpenProject == true or isOpenProject == "true" then
            local scenarioId, sendTime, publishDate, version, eventAddr,
                  magnitude, longitude, latitude
            scenarioId = tjsondata["scenarioId"]
            sendTime = tjsondata["sendTime"]
            publishDate = tjsondata["publishDate"]
            version = tjsondata["version"]
            eventAddr = tjsondata["eventAddr"]
            magnitude = tjsondata["magnitude"]
            longitude = tjsondata["longitude"]
            latitude = tjsondata["latitude"]
            if not tjsondata["flashLight"] then
                flashLight = 0
            else
                flashLight = tonumber(tjsondata["flashLight"])
            end

            if not tjsondata["expectedCountdown"] then
                countDownSDrill = 0
            else
                countDownSDrill = tonumber(tjsondata["expectedCountdown"])
            end
            if not tjsondata["localIntensity"] then
                quake_intensity = 0
            else
                quake_intensity = tonumber(tjsondata["localIntensity"])
            end
            if tjsondata["status"] == "0" then
                msgCode = "0199"
            elseif tjsondata["status"] == "1" then
                msgCode = "0201"
            end
            local sendMsg = ""
            sendMsg = "{" .. "\"merchantNo\":\"" .. merchantNo ..
                          "\",\"msgType\":\"2\",\"msgId\":\"" .. msgId ..
                          "\",\"scenarioId\":\"" .. scenarioId ..
                          "\",\"serialNumber\":\"" .. serialNumber ..
                          "\",\"receiveTime\":\"" .. sysTime ..
                          "\",\"version\":\"" .. version .. "\"}"
            eqlogInfo = "[" .. sysTime .. "]" ..
                            "[回传第三方系统信息:]" .. sendMsg .."回复主题："..ackTopic.. "\n"
            logGenerator.generateLogTask(eqlogInfo, "log")
            mqttOutMsgThird.insertMsg(ackTopic, sendMsg, 0)
        end
    else
        if not tjsondata["1"] then
            countDownSDrill = 0
        else
            countDownSDrill = tonumber(tjsondata["1"])
        end
        if not tjsondata["2"] then
            quake_intensity = 0
        else
            quake_intensity = tonumber(tjsondata["2"])
        end
        if tjsondata["16"] then msgCode = tjsondata["16"] end
        log.info("tacountDownSDrillg", countDownSDrill, "quake_intensity",
                 quake_intensity, "msgCode", msgCode)
    end
    if msgCode == "0199" or quake_intensity == 0 then
        local strAlertCancel = ""
        sysTime = utilsBySelf.GetSystemTime()
        eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                        "预警演习取消！级\n"
        audio.stop()
        if cancelCount > 0 then
            for i = 1, cancelCount do
                strAlertCancel = strAlertCancel .. "预警演习取消,"
            end
            audio.play(TTS, "TTS", strAlertCancel, 7)
            sys.wait(2200 * cancelCount)
        end
        if toneDowns > 0 then toneBreak = true end
        if lampDowns > 0 then lampBreak = true end
        if relayDowns > 0 then relayBreak = true end
        if not doEmergencyLightOpen then emergencyLightOpenBreak = true end
        if signalDowns > 0 then signalBreak = true end
        while not doSignalTask do sys.wait(800) end
        if not send433RFSignal.TimeId then
            send433RFSignal.InterruptSendMsg = false
            send433RFSignal.sendMsgTask()
        end
    else
        sysTime = utilsBySelf.GetSystemTime()
        eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                        "[预警演习:]到达秒数:" .. countDownSDrill ..
                        "s,地震烈度:" .. quake_intensity .. "级\n"
        if toneDowns > 0 then toneBreak = true end
        if lampDowns > 0 then lampBreak = true end
        if relayDowns > 0 then relayBreak = true end
        if not doEmergencyLightOpen then emergencyLightOpenBreak = true end
        if signalDowns > 0 then signalBreak = true end
        while not DoLampTask do sys.wait(800) end
        -- 报警灯任务
        log.info("alertLight", alertLight)
        if intensity2Threshold(quake_intensity) >= alertLight and DoLampTask then
            log.info("enter alertLight")
            sys.taskInit(alarmLampOperationTask, countDownSDrill, publisherId)
        else
            sysTime = utilsBySelf.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                            "[不满足报警灯临界值：]" ..
                            "烈度转阈值：" ..
                            tostring(intensity2Threshold(quake_intensity)) ..
                            ",报警灯预设值：" .. tostring(alertLight) ..
                            "[执行报警灯任务:]" ..
                            tostring(not DoLampTask) .. "\n"
        end
        while not doSignalTask do sys.wait(800) end
        -- 433信号发送任务
        if (intensity2Threshold(quake_intensity) >= emergencyLamp or
            intensity2Threshold(quake_intensity) >= alertSound) and enable433 and
            doSignalTask then
            log.info("433send")
            sys.wait(200)
            sys.taskInit(send433SignalTask, countDownSDrill)
            sys.taskInit(emergencyLightOpenTask)
        else
            sysTime = utilsBySelf.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                            "[阈值，发送433，执行发送433信号存在条件不满足]" ..
                            "烈度转阈值：" ..
                            tostring(intensity2Threshold(quake_intensity)) ..
                            ",设定阈值：" .. alertSound ..
                            ",是否发送433:" .. tostring(enable433) ..
                            "执行发送433信号任务:" ..
                            tostring(not doSignalTask) .. "\n"
        end
        log.info("alertSound", alertSound)
        while not doToneTask do sys.wait(800) end
        -- 报警音任务
        log.info("alertSound", alertSound)
        if intensity2Threshold(quake_intensity) >= countDown and doToneTask and
            quake_intensity >= configIntensity then
            log.info("alertSound enter")
            sys.wait(200)
            sys.taskInit(alarmVoiceTask, countDownSDrill)
            --[[ if doToneTask and quake_intensity >= configIntensity then
            log.info("alertSound enter")
            sys.wait(200)
            sys.taskInit(alarmVoiceTask, countDownSDrill) ]]
        else
            sysTime = utilsBySelf.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                            "[不满足报警音临界值：]" ..
                            "烈度阈值：" ..
                            tostring(intensity2Threshold(quake_intensity)) ..
                            ",报警音预设值：" .. countDown ..
                            ",[执行报警音任务:]" ..
                            tostring(not doToneTask) .. "\n"
        end
        -- 继电器动作任务
        while not doRelayTask do sys.wait(800) end
        if intensity2Threshold(quake_intensity) >= relay and doRelayTask and
            quake_intensity >= configIntensity then
            sys.wait(200)
            sys.taskInit(relayTask, countDownSDrill)
        else
            sysTime = utilsBySelf.GetSystemTime()
            eqlogInfo = eqlogInfo .. "[" .. sysTime .. "]" ..
                            "[不满足报警音临界值：]" ..
                            "烈度阈值：" ..
                            tostring(intensity2Threshold(quake_intensity)) ..
                            ",报警音预设值：" .. countDown ..
                            ",[执行报警音任务:]" ..
                            tostring(not doToneTask) .. "\n"
        end
    end
    if eqlogInfo ~= "" and eqlogInfo ~= false then
        log.info("生成eq日志")
        logGenerator.generateLogTask(eqlogInfo, "log")
    end
    if errInfo ~= "" and errInfo ~= false then
        log.info("生成错误日志", errInfo)
        logGenerator.generateLogTask(errInfo, "log")
    end
end
